#pragma noce

#include <map>
#include <string>
#include <memory>

#include <sys/socket.h>
#include <sys/types.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <mutex>
#include "Logger.hpp"

using namespace std;

using namespace LogMudule;

namespace ChatRoomMudule
{

    class Observer // 观察者虚基类
    {
    public:
        virtual void GetMessage(int sockfd,const string &msg) = 0;
        virtual ~Observer()
        {
        }
    };

    class User : public Observer // 观察者子类：用户类
    {
    public:
        User(uint32_t ip, uint16_t port)
            : _ip(ip),
              _port(port)
        {
        }
        virtual void GetMessage(int sockfd, const string &msg)
        {
            struct sockaddr_in addr;

            addr.sin_family = AF_INET;         // 网络协议族
            addr.sin_addr.s_addr = htonl(_ip); // 主机序列转网络序列
            addr.sin_port = htons(_port);      // 主机序列转网络序列

            char ip_buf[100] = {0};
            uint32_t inet_ip = htonl(_ip); // 网络序列的ip

            // 把网络序列的4字节IP,转成主机序列的点分十进制的IP
            inet_ntop(AF_INET, &inet_ip, ip_buf, sizeof(ip_buf));
            string info="ip: ";
            info+=inet_ip;
            info+=("，port: "+to_string(_port)+"# ");
            info+=msg;

            
            int n = sendto(sockfd, info.c_str(), info.size(), 0, (sockaddr *)&addr, sizeof(addr));
            if (n > 0)
            {
                LOG(LogLevel::DEBUG) << "成功向ip:" << ip_buf << " ,port: " << _port << " 的用户发送消息: " << msg;
            }
            else
            {
                LOG(LogLevel::ERROR) << "向ip:" << ip_buf << " ,port: " << _port << " 的用户发送消息时：" << ErrortoString(common_error);
            }
        }

    private:
        uint32_t _ip;
        uint16_t _port;
    };

    class ChatRoom // 被观察者：聊天室类
    {
    public:
        bool InsetUser(const struct sockaddr_in &user)//添加新用户到聊天室
        {
            if (isExist(user))//判断用户是否在聊天室
            {
                return false;
            }

            lock_guard<mutex> m(_mutex);//保护共享资源：_ob_table

            uint32_t ip = ntohl(user.sin_addr.s_addr); // 网络序列转主机序列
            uint16_t port = ntohs(user.sin_port);      // 网络序列转主机序列

            //添加用户
            _ob_table.insert({make_pair(ip, port), make_unique<User>(ip, port)});

            return true;
        }
        void Broadcast(int sockfd,const string &msg)//通知多余观察者
        {
            lock_guard<mutex> m(_mutex);//保护共享资源：_ob_table
            for (const auto &e : _ob_table)
            {
                (e.second)->GetMessage(sockfd,msg);//调用观察者自己的接口进行通知
            }
        }
        bool isExist(const struct sockaddr_in &user)//判断用户是否在聊天室
        {
            lock_guard<mutex> m(_mutex);//保护共享资源：_ob_table

            uint32_t ip = ntohl(user.sin_addr.s_addr); // 网络序列转主机序列
            uint16_t port = ntohs(user.sin_port);      // 网络序列转主机序列

            if (_ob_table.find({ip, port}) == _ob_table.end())
            {
                return false;
            } 
            return true;
        }

    private:
        map<pair<uint32_t,uint16_t>, unique_ptr<Observer>> _ob_table; // 存储所有观察我的观察者
        mutex _mutex;
    };
}